Java JavaScript Python C# C C++ Go Kotlin PHP Swift R Ruby TypeScript Scala SQL Perl rust VisualBasic Matlab Julia

Inheritance → Operator Overloading

Inheritance

Operator Overloading

Operator Overloading in Python

Operator overloading is a powerful feature in object-oriented programming (OOP) that allows you to redefine the behavior of built-in operators (like `+`, `-`, `*`, `/`, `==`, etc.) for your custom classes. Instead of these operators performing their default actions on built-in data types, they can perform specialized actions tailored to the objects of your class. This enhances code readability and makes it more intuitive.

How it Works in Python

Python achieves operator overloading through special methods, also known as "magic methods" or "dunder methods" (because they are surrounded by double underscores, e.g., `__add__`). When you use an operator with objects of your class, Python internally calls the corresponding special method. 1. Adding Vectors
Operator Overloading basic example class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): # Overloading the '+' operator if isinstance(other, Vector): return Vector(self.x + other.x, self.y + other.y) else: raise TypeError("Can only add Vectors to other Vectors") def __str__(self): #For printing the Vector object in a readable format return f"({self.x}, {self.y})" v1 = Vector(2, 3) v2 = Vector(4, 1) v3 = v1 + v2 # Calls __add__ method print(v3) # Output: (6, 4) #Trying to add a non-vector will raise a TypeError try: v4 = v1 + 5 except TypeError as e: print(e) #Output: Can only add Vectors to other Vectors

Output

(6, 4) Can only add Vectors to other Vectors
Here, the `__add__` method defines how two `Vector` objects are added together. The `isinstance` check ensures that we're only adding vectors, preventing unexpected behavior. The `__str__` method is crucial for a user-friendly output.
2. Comparing Vectors Let's add the ability to compare vectors for equality:
Comparing Vectors class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): # Overloading the '+' operator if isinstance(other, Vector): return Vector(self.x + other.x, self.y + other.y) else: raise TypeError("Can only add Vectors to other Vectors") def __str__(self): #For printing the Vector object in a readable format return f"({self.x}, {self.y})" v1 = Vector(2, 3) v2 = Vector(4, 1) v3 = v1 + v2 # Calls __add__ method #Trying to add a non-vector will raise a TypeError try: v4 = v1 + 5 except TypeError as e: print(e) #Output: Can only add Vectors to other Vectors def __eq__(self, other): # Overloading the '==' operator if isinstance(other, Vector): return self.x == other.x and self.y == other.y return False v1 = Vector(2, 3) v2 = Vector(2, 3) v3 = Vector(4, 1) print(v1 == v2) print(v1 == v3) print(v1 == (2,3))

Output

Can only add Vectors to other Vectors False False False
The `__eq__` method defines how equality is checked between `Vector` objects. Again, a type check is included for robustness.
3. Multiplying a Vector by a Scalar We can extend the functionality to multiply a vector by a scalar (a single number):
Multiplying a Vector by a Scalar class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): # Overloading the '+' operator if isinstance(other, Vector): return Vector(self.x + other.x, self.y + other.y) else: raise TypeError("Can only add Vectors to other Vectors") def __str__(self): #For printing the Vector object in a readable format return f"({self.x}, {self.y})" v1 = Vector(2, 3) v2 = Vector(4, 1) v3 = v1 + v2 # Calls __add__ method print(v3) # Output: (6, 4) #Trying to add a non-vector will raise a TypeError try: v4 = v1 + 5 except TypeError as e: print(e) #Output: Can only add Vectors to other Vectors def __mul__(self, scalar): # Overloading the '*' operator if isinstance(scalar, (int, float)): return Vector(self.x * scalar, self.y * scalar) else: raise TypeError("Can only multiply Vectors by numbers") v1 = Vector(2, 3) try: v5 = v1 * "hello" except TypeError as e: print(e) # Output: Can only multiply Vectors by numbers

Output

(6, 4) Can only add Vectors to other Vectors can't multiply sequence by non-int of type 'Vector'
The `__mul__` method handles multiplication with a scalar. Note that if we want to define multiplication of two vectors (e.g., dot product), we'd need a separate method (`__matmul__` for the `@` operator might be more appropriate depending on the desired behaviour).
4. String Representation (More Elaborate) We can make our string representation more informative:
String Representation (More Elaborate) class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): # Overloading the '+' operator if isinstance(other, Vector): return Vector(self.x + other.x, self.y + other.y) else: raise TypeError("Can only add Vectors to other Vectors") def __str__(self): #For printing the Vector object in a readable format return f"({self.x}, {self.y})" v1 = Vector(2, 3) v2 = Vector(4, 1) v3 = v1 + v2 # Calls __add__ method #Trying to add a non-vector will raise a TypeError try: v4 = v1 + 5 except TypeError as e: print(e) #Output: Can only add Vectors to other Vectors def __str__(self): return f"Vector(x={self.x}, y={self.y})" v1 = Vector(2,3) print(v1) #Output: Vector(x=2, y=3)

Output

Can only add Vectors to other Vectors (2, 3)

Important Considerations Consistency: When overloading operators, maintain consistency with the usual mathematical or logical meaning of those operators. Type Handling: Always include type checks to handle cases where the operator might be used incorrectly (as shown in the examples above). Error Handling: Raise appropriate exceptions for invalid operations. Symmetry: For operators like `+` and `*`, consider overloading both `__add__` and `__radd__` (right-hand add) to handle cases like `5 + v1` where the vector isn't the left operand. The same applies for `__mul__` and `__rmul__`. Operator overloading significantly enhances the elegance and expressiveness of your Python code when working with custom classes. It allows you to create intuitive and readable interfaces that mimic the behavior of built-in types, improving code maintainability and understandability. Remember to always prioritize clarity and robustness in your implementations.

Tutorials